/**********************************************************************
 * system3.c
 *
 * AUTOR:	SELETZ
 *
 * Implements several POST routines for PT System 3 platform
 *
 * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@www.eletztrick.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ident "$Id: system3.c,v 1.8 2002/01/07 19:36:15 seletz Exp $"

/**********************************************************************
 * Includes
 */
#ifdef HAVE_CONFIG_H
# include <blob/config.h>
#endif

#include <blob/types.h>
#include <blob/errno.h>
#include <blob/util.h>
#include <blob/command.h>
#include <blob/init.h>
#include <blob/serial.h>
#include <blob/time.h>
#include <blob/sa1100.h>
#include <blob/sa1111.h>

#include <blob/lcd.h>

/**********************************************************************
 * defines
 */
#define MEM(adr)	(*((u32*)adr))
#define SET(reg,bit)	((reg) |= (1<<(bit)))
#define CLR(reg,bit)	((reg) &= ~(1<<(bit)))

/* Optimization barrier */
/* The "volatile" is due to gcc bugs */
#define barrier() __asm__ __volatile__("": : :"memory")

#define	CPLD_BASE	(0x10000000)
#define	CPLD_ID		(CPLD_BASE + 0x00)
#define	CPLD_IRQ	(CPLD_BASE + 0x24)
#define	CPLD_0		(CPLD_BASE + 0x90)
#define	CPLD_1		(CPLD_BASE + 0xA0)
#define	CPLD_2		(CPLD_BASE + 0xB0)

/**********************************************************************
 * types
 */

/**********************************************************************
 * program globals
 */

/**********************************************************************
 * module globals
 */

/**********************************************************************
 * prototypes
 */
static void sa1111_init();

/*********************************************************************/
/*********************************************************************/
/*********************************************************************/

#if defined(CONFIG_LCD_SUPPORT)

__initlist(sa1111_init,		INIT_LEVEL_INITIAL_HARDWARE);

static void sa1111_init()
{
	/* switch on clock for sa1111 */
	GAFR |= GPIO_32_768kHz;
	GPDR |= GPIO_32_768kHz;
	TUCR = TUCR_3_6864MHz;

	/* Now, set up the PLL and RCLK in the SA-1111: */
	SBI_SKCR = SKCR_PLL_BYPASS | SKCR_RDYEN | SKCR_OE_EN;
	msleep(100);
	SBI_SKCR = SKCR_PLL_BYPASS | SKCR_RCLKEN | SKCR_RDYEN | SKCR_OE_EN;

	SerialOutputString( "SA1111 ID: " );
	SerialOutputHex( SBI_SKID );
	SerialOutputString( "\n" );

	/*
	 * SA-1111 Register Access Bus should now be available. Clocks for
	 * any other SA-1111 functional blocks must be enabled separately
	 * using the SKPCR.
	 */
	SKPCR |= SKPCR_DCLKEN | SKPCR_PWMCLKEN;

	/*
	 * If the system is going to use the SA-1111 DMA engines, set up
	 * the memory bus request/grant pins. Also configure the shared
	 * memory controller on the SA-1111 (SA-1111 Developer's Manual,
	 * section 3.2.3) and power up the DMA bus clock:
	 */
	GAFR |= (GPIO_MBGNT | GPIO_MBREQ);
	GPDR |= GPIO_MBGNT;
	GPDR &= ~GPIO_MBREQ;
	TUCR |= TUCR_MR;

	SBI_SMCR = (SMCR_DTIM | SMCR_MBGE |
		FInsrt(FExtr(MDCNFG, MDCNFG_SA1110_DRAC0), SMCR_DRAC) |
		((FExtr(MDCNFG, MDCNFG_SA1110_TDL0)==3) ? SMCR_CLAT : 0));
}




static void system3_init_hardware(void)
{
	/* select serial driver */
	serial_driver = &sa11x0_serial_driver;
}

__initlist(system3_init_hardware, INIT_LEVEL_DRIVER_SELECTION);


/**********************************************************************
 * Overwrite LCD functions special for this platform
 */
int lcd_power_up( void )
{
	SET( MEM( CPLD_0 ), 7 );

	PB_DDR = 0xFFFFFFFF;
	SKPEN0 = 1;
	SKPEN1 = 1;

	lcd_contrast( 0x95 );
	lcd_brightness( 240 );
	lcd_backlight_on();
	return 0;
}

int lcd_power_down( void )
{
	SKPEN0 = 0;
	SKPEN0 = 0;
	CLR( MEM( CPLD_0 ), 7 );
	return 0;
}

int lcd_backlight_on( void )
{
	SET( MEM( CPLD_0 ), 2 );
	return 0;
}

int lcd_backlight_off( void )
{
	CLR( MEM( CPLD_0 ), 2 );
	return 0;
}

int lcd_contrast( int value )
{
	SKPWM0 = value;
	return 0;
}

int lcd_brightness( int value )
{
	SKPWM1 = value;
	return 0;
}

#endif // defined(CONFIG_LCD_SUPPORT)


/**********************************************************************
 * static functions
 */

#if 1
#define SMC_BASE	0x18000000
#define	BANK_SELECT		14
#define LAN91C96_ECOR	0x0
#define LAN91C96_ECSR	0x2

#define ECOR_RESET	0x80
#define ECOR_LEVEL_IRQ	0x40
#define ECOR_WR_ATTRIB	0x02
#define ECOR_ENABLE	0x01

#define ECSR_IOIS8	0x20
#define ECSR_PWRDWN	0x04
#define ECSR_INT	0x02
#define SMC_inb( r )  (*((volatile u8 *)(base+((r)<<2))))
static inline unsigned short __SMC_inw(unsigned base, int r)
{
	unsigned char b1, b2;
	msleep(1);
	b1 = SMC_inb(r);
	msleep(1);
	b2 = SMC_inb(r+1);
	return (b2 << 8) | b1;
}
#define SMC_inw(r) __SMC_inw(base, r)
#define SMC_outb( d, r )  (*((volatile u8 *)(base+((r)<<2))) = (u8)(d))
#define SMC_outw( d, r )  do { \
		     msleep(1);\
                     SMC_outb((d), r); \
		     msleep(1);\
		     SMC_outb((d)>>8, (r)+1);} while (0)
static int smctest( int argc, char *argv[] )
{
	u32	base	= (u32)SMC_BASE;
	u32	*attr;
	u16	bank;

	/* 0x1a020000 */
	attr	= (u32 *)(((u32)base | (1<<25)) + (0x8000*4));

	/* enable the device */
	attr[LAN91C96_ECOR] |= ECOR_RESET;
	msleep(100);

	/* the device will ignore all writes to the enable bit while reset is
	 * asserted, even if the reset bit is cleared in the same write. Must
	 * clear reset first, then enable the device.
	 */
	attr[LAN91C96_ECOR] &= ~ECOR_RESET;
	attr[LAN91C96_ECOR] |= ECOR_ENABLE;

	/* force byte mode */
	attr[LAN91C96_ECSR] |= ECSR_IOIS8;

	bank = SMC_inw( BANK_SELECT );
	SerialOutputString( "bank " );
	SerialOutputHex( bank & 0xffff );
	SerialOutputString( "\n" );

	SMC_outw( 0, BANK_SELECT );
	bank = SMC_inw( BANK_SELECT );
	SerialOutputString( "bank " );
	SerialOutputHex( bank & 0xffff );
	SerialOutputString( "\n" );

	return 0;
}
static char smctesthelp[] = "test smc 91c96 ethernet chip\n";
__commandlist(smctest, "smctest", smctesthelp);
#endif
